# -*- coding: utf-8 -*-

coords1d = (-1, 0, 1)

def coords3dGenerator():
    for z in coords1d:
        for y in coords1d:
            for x in coords1d:
                if x != 0 or y != 0 or z != 0:
                    yield (x, y, z)

coords3d = tuple(coords3dGenerator())

normal = (
     0,  1,  2,
     3,  4,  5,
     6,  7,  8,

     9, 10, 11,
    12,     13,
    14, 15, 16,

    17, 18, 19,
    20, 21, 22,
    23, 24, 25,
)

xflip = (
     2,  1,  0,
     5,  4,  3,
     8,  7,  6,

    11, 10,  9,
    13,     12,
    16, 15, 14,

    19, 18, 17,
    22, 21, 20,
    25, 24, 23,
)

yflip = (
     6,  7,  8,
     3,  4,  5,
     0,  1,  2,

    14, 15, 16,
    12,     13,
     9, 10, 11,

    23, 24, 25,
    20, 21, 22,
    17, 18, 19,
)

zflip = (
    17, 18, 19,
    20, 21, 22,
    23, 24, 25,

     9, 10, 11,
    12,     13,
    14, 15, 16,

     0,  1,  2,
     3,  4,  5,
     6,  7,  8,
)

xyflip = tuple(xflip[i] for i in yflip)
yzflip = tuple(yflip[i] for i in zflip)
zxflip = tuple(zflip[i] for i in xflip)

xrot = (
    17, 18, 19,
     9, 10, 11,
     0,  1,  2,

    20, 21, 22,
    12,     13,
     3,  4,  5,

    23, 24, 25,
    14, 15, 16,
     6,  7,  8,
)
xrot2 = tuple(xrot[i] for i in xrot)
xrot3 = tuple(xrot2[i] for i in xrot)

yrot = (
     2, 11, 19,
     5, 13, 22,
     8, 16, 25,

     1, 10, 18,
     4,     21,
     7, 15, 24,

     0,  9, 17,
     3, 12, 20,
     6, 14, 23,
)
yrot2 = tuple(yrot[i] for i in yrot)
yrot3 = tuple(yrot2[i] for i in yrot)

zrot = (
     6,  3,  0,
     7,  4,  1,
     8,  5,  2,

    14, 12,  9,
    15,     10,
    16, 13, 11,

    23, 20, 17,
    24, 21, 18,
    25, 22, 19,
)
zrot2 = tuple(zrot[i] for i in zrot)
zrot3 = tuple(zrot2[i] for i in zrot)

def isAdj(p1, p2):
    if p1 == p2:
        return False
    for x1, x2 in zip(p1, p2):
        if abs(x1 - x2) > 1:
            return False
    return True

def printCubePoints(point_set):
    print '  z =-1  z = 0  z = 1'
    for y in coords1d:
        print ' ',
        for z in coords1d:
            for x in coords1d:
                if (x, y, z) in point_set:
                    print '*',
                elif x == y == z == 0:
                    print 'X',
                else:
                    print '.',
            print '',
        print ''
    print '------------------------------'

def printCube(point_idx_list):
    point_set = set(coords3d[i] for i in point_idx_list)
    printCubePoints(point_set)

OVERLAP = 1
NOTENOUGH = 2
FILLED = 3
def pointsTest(point_idx_list):
    point_set = set(coords3d[i] for i in point_idx_list)
    directions_set = set(point_set)
    for p in point_set:
        new_d = tuple(-x for x in p)
        if new_d in directions_set:
            return OVERLAP
        directions_set.add(new_d)
    for p1 in point_set:
        for p2 in point_set:
            if isAdj(p1, p2):
                new_d = tuple(x1 - x2 for x1, x2 in zip(p1, p2))
                if new_d in directions_set:
                    return OVERLAP
                directions_set.add(new_d)
    if len(directions_set) == 26:
        return FILLED
    else:
        return NOTENOUGH

print '='*30

allowed_ranges = range(26)
results = set()

def test(idx_range, indexes, depth):
    if not idx_range or not depth:
        return

    notenough = []
    for idx, idx_pos in zip(idx_range, range(len(idx_range))):
        test_val = pointsTest(indexes + [idx])
        if test_val == NOTENOUGH:
            notenough.append((idx, idx_pos))
        elif test_val == FILLED:
            print 'found!'
            results.add(tuple(indexes + [idx]))
    for idx, idx_pos in notenough:
        test(idx_range[idx_pos + 1:], indexes + [idx], depth - 1)

test(allowed_ranges, [], 6)

print '='*80

def transform(indexes, flip):
    return tuple(sorted(flip[i] for i in indexes))

results_filtered = set()
for r in results:
    doubled = False
    for t1 in [xflip, yflip, zflip, xyflip, yzflip, zxflip]:
        if transform(r, t1) in results_filtered:
            doubled = True
            break
        for t2 in [xrot, xrot2, xrot3, yrot, yrot2, yrot3, zrot, zrot2, zrot3]:
            if transform(r, t2) in results_filtered or transform(transform(r, t2), t1) in results_filtered:
                doubled = True
                break
        if doubled:
            break
    if not doubled:
        results_filtered.add(r)

print 'filtered from %d to %d' % (len(results), len(results_filtered))

results = results_filtered
print results
for r in results:
    printCube(r)

